package com.jboom.templates.statemachine.spring.service;

import com.jboom.templates.statemachine.spring.constant.OrderStatusEnum;
import com.jboom.templates.statemachine.spring.entity.Order;
import com.jboom.templates.statemachine.spring.event.OrderEvent;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.statemachine.StateMachine;
import org.springframework.statemachine.persist.StateMachinePersister;
import org.springframework.stereotype.Service;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.LongAdder;

/**
 * @author zhangwen
 * @date 2023/5/25 13:17
 */
@Slf4j
@Service
public class OrderServiceImpl implements OrderService {

    @Resource
    private StateMachine<OrderStatusEnum, OrderEvent> orderStateMachine;

    @Resource
    private StateMachinePersister<OrderStatusEnum, OrderEvent, Order> persister;

    LongAdder idAdder = new LongAdder();

    Map<Long, Order> orderRepository = new ConcurrentHashMap<>();

    @Override
    public Order create() {
        Order order = new Order();
        idAdder.increment();
        order.setId(idAdder.longValue());
        order.setOrderStatus(OrderStatusEnum.WAIT_PAY);
        orderRepository.put(order.getId(), order);
        return order;
    }

    @Override
    public Order pay(Long id) {
        Order order = orderRepository.get(id);
        log.info("线程 {},尝试支付 {}", Thread.currentThread().getName(), id);
        Message<OrderEvent> message = MessageBuilder.withPayload(OrderEvent.PAYED).setHeader("order", order).build();
        sendEvent(message,order);
        return orderRepository.get(id);
    }

    @Override
    public Order deliver(Long id) {
        Order order = orderRepository.get(id);
        log.info("线程 {},尝试发货 {}", Thread.currentThread().getName(), id);
        Message<OrderEvent> message = MessageBuilder.withPayload(OrderEvent.DELIVERED).setHeader("order", order).build();
        sendEvent(message,order);
        return orderRepository.get(id);
    }

    @Override
    public Order receive(Long id) {
        Order order = orderRepository.get(id);
        log.info("线程 {},尝试收货 {}", Thread.currentThread().getName(), id);
        Message<OrderEvent> message = MessageBuilder.withPayload(OrderEvent.RECEIVEED).setHeader("order", order).build();
        sendEvent(message,order);
        return orderRepository.get(id);
    }

    private synchronized void sendEvent(Message<OrderEvent> message, Order order) {
        try {
            orderStateMachine.start();
            //尝试恢复状态机的状态
            persister.restore(orderStateMachine,order);
            orderStateMachine.sendEvent(message);
            persister.persist(orderStateMachine,order);
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            orderStateMachine.stop();
        }
    }

    @Override
    public void printAllOrders(){
        orderRepository.values().forEach(System.out::println);
    }
}
